package com.rdxer.service;

import com.rdxer.dataview.*;
import com.rdxer.core.ex.ListEx;
import com.rdxer.core.ex.ObjectEx;
import com.rdxer.core.utils.IdWorker;
import com.rdxer.model.*;
import com.rdxer.repository.AnswerSheetRepository;
import lombok.Getter;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

/**
 * Department 服务层
 */
@Service
@Getter
public class AnswerSheetService implements CRUDPageServiceInterface<AnswerSheet, String> {


    @Autowired
    private AnswerSheetRepository repository;
    @Autowired
    private PaperQuestionRelationService relationService;
    @Autowired
    private QuestionService questionService;

    @Autowired
    private IdWorker idWorker;

    public AnswerSheet getAnswerSheetByPaperAndUserId(String paperId, String userId) {

        List<AnswerSheet> allByPaperId = repository.findAllByPaperIdAndUserId(paperId, userId);

        if (ListEx.isEmpty(allByPaperId)) {
            AnswerSheet answerSheet = AnswerSheet.builder()
                    .createDate(System.currentTimeMillis())
                    .paperId(paperId)
                    .resolve(false)
                    .userId(userId)
                    .build();

            save(answerSheet);
            return answerSheet;
        }

        return allByPaperId.get(0);
    }


    @Autowired
    AnswerService answerService;

    public AnswerSheet commit(String id, List<CommitAnswerSheetDV> answerSheetDV) {
        AnswerSheet answerSheet = findById(id);
        // 0. 清空以前的 提交记录
        answerService.clearByAnswerSheet(id);
        // 1. 更新答卷信息
        answerSheet.setEndDate(System.currentTimeMillis());
        answerSheet.setTestDuration(answerSheet.getEndDate() - answerSheet.getCreateDate());
        save(answerSheet);
        // 2. 保存答卷答题信息
        for (CommitAnswerSheetDV dv : answerSheetDV) {
            answerService.setAnswer(answerSheet, dv);
        }
        // 3. 批改 客观分试题
        reviewObj(answerSheet, answerSheetDV);
        return answerSheet;
    }

    private void reviewObj(AnswerSheet answerSheet, List<CommitAnswerSheetDV> answerSheetDV) {
        Double sumScore = 0.0;
        for (CommitAnswerSheetDV dv : answerSheetDV) {
            Answer answer = answerService.findAnswer(answerSheet.getId(), dv.getId());
            answer.setCorrect(false);
            answer.setScore(0.0);
            Question.Type type = Question.Type.valueOf(dv.getQuestion().getType());
            switch (type) {
                case Single:
                case Judge:
                case Multi:
                    List<AnswerOption> answerOption = answerService.findAnswerOption(answer.getId());
                    List<QuestionOption> questionCorrectOption = dv.getQuestionOption()
                            .stream()
                            .filter(v -> v.getCorrect())
                            .collect(Collectors.toList());
                    long errorCount = answerOption.stream().filter(v -> v.getCorrect() == false || v.getCorrect() == null).count();
                    if (errorCount > 0) {
                        break;
                    }
                    if (answerOption.size() != questionCorrectOption.size()) {
                        break;
                    }
                    answer.setCorrect(true);
                    answer.setScore(dv.getQuestion().getScore());
                    break;
                case Completion:
                case FreeResponse:
                    answer.setCorrect(null);
                    answer.setScore(null);
                    break;
            }
            answerService.save(answer);
            sumScore += answer.getScore() == null ? 0 : answer.getScore();
        }
        answerSheet.setObjectiveScore(sumScore);
        if (answerSheetDV.stream()
                .map(dv ->
                        Question.Type.valueOf(dv.getQuestion().getType())
                ).filter(v ->
                        v == Question.Type.FreeResponse || v == Question.Type.Completion
                )
                .count() == 0) {
            answerSheet.setSubjectiveScore(0.0);
            answerSheet.setResolve(true);
        }
        answerSheet.setScore(sumScore);
        save(answerSheet);
    }


    private void reviewObj2(AnswerSheet answerSheet, List<CommitAnswerSheetDV> answerSheetDV) {
        double sumScore = 0.0;
        for (CommitAnswerSheetDV dv : answerSheetDV) {
            Answer answer = answerService.findAnswer(answerSheet.getId(), dv.getId());
            Question.Type type = Question.Type.valueOf(dv.getQuestion().getType());
            switch (type) {
                case Single:
                case Judge:
                case Multi:
                    List<AnswerOption> answerOption = answerService.findAnswerOption(answer.getId());
                    List<QuestionOption> questionCorrectOption = dv.getQuestionOption()
                            .stream()
                            .filter(v -> v.getCorrect())
                            .collect(Collectors.toList());
                    long errorCount = answerOption.stream().filter(v -> v.getCorrect() == false || v.getCorrect() == null).count();
                    if (errorCount > 0 || answerOption.size() != questionCorrectOption.size()) {
                        break;
                    }
                    answer.setCorrect(true);
                    answer.setScore(dv.getQuestion().getScore());
                    break;
                case Completion:
                case FreeResponse:
                    answer.setCorrect(null);
                    answer.setScore(null);
                    break;
            }
            answerService.save(answer);
            sumScore += answer.getScore() == null ? 0 : answer.getScore();
        }
        answerSheet.setObjectiveScore(sumScore);
        if (answerSheetDV.stream().map(dv -> Question.Type.valueOf(dv.getQuestion().getType()))
                .filter(v -> v == Question.Type.FreeResponse || v == Question.Type.Completion)
                .count() == 0) {
            answerSheet.setSubjectiveScore(0.0);
            answerSheet.setResolve(true);
        }
        answerSheet.setScore(sumScore);
        save(answerSheet);
    }


    public List<AnswerSheet> findAllByPaper(String id) {
        List<AnswerSheet> list = repository.findAllByPaperId(id);
        return list;
    }

    public List<AnswerSheet> getAnswerSheetListByUserId(String id) {
        List<AnswerSheet> list = repository.findAllByUserId(id);
        return list;
    }

    @Autowired
    PaperService paperService;

    public List<AnswerSheetDV> getAnswerSheetDVListByUserId(String id) {
        List<AnswerSheet> sheetList = getAnswerSheetListByUserId(id);

        List<AnswerSheetDV> rs = new ArrayList<>();

        for (AnswerSheet sheet : sheetList) {
            AnswerSheetDV r = AnswerSheetDV.builder().build();

            BeanUtils.copyProperties(sheet, r);

            Paper byId = paperService.findById(sheet.getPaperId());

            r.setPaper(byId);

            rs.add(r);
        }

        return rs;
    }

    public List<PaperQuestionDV> findPaperQuestionDataAndV(String paperId, String id) {
        List<PaperQuestionDV> questionDVList = paperService.findAllQuestion(paperId);

        for (PaperQuestionDV dv : questionDVList) {
            AnswerDV answerDV = answerService.findAnswerDV(id, dv.getId());
            dv.setAnswerDV(answerDV);
            dv.setQuestionOptionAndAnswer(new ArrayList<>());
            Question.Type type = Question.Type.valueOf(dv.getQuestion().getType());
            switch (type) {
                case Single:
                case Judge:
                    String v = ObjectEx.get(() -> answerDV.getOptionList().get(0).getQuestionOptionId());
                    dv.setV(v);
                    break;
                case Multi:
                    List<String> strings = ObjectEx.get(() -> answerDV.getOptionList().stream().map(AnswerOption::getQuestionOptionId).collect(Collectors.toList()));
                    dv.setV(strings);
                    break;
                case Completion:
                case FreeResponse:
                    dv.setV(answerDV.getContent());
                    break;
            }
            for (QuestionOption option : dv.getQuestionOption()) {
                QuestionOptionDV o2 = new QuestionOptionDV();
                BeanUtils.copyProperties(option, o2);
                o2.setIsSelect(false);
                o2.setIsError(false);
                for (AnswerOption answerOption : answerDV.getOptionList()) {
                    if (answerOption.getQuestionOptionId().equals(option.getId())) {
                        o2.setIsSelect(true);
                        break;
                    }
                }
                if (o2.getIsSelect() && !o2.getCorrect() || !o2.getIsSelect() && o2.getCorrect()) {
                    o2.setIsError(true);
                }
                dv.getQuestionOptionAndAnswer().add(o2);
            }
        }

        return questionDVList;
    }

    public boolean setAnswerScore(String answerid, Double score) {
        Answer answer = answerService.findById(answerid);
        answer.setScore(score);
        answer.setCorrect(true);
        answerService.save(answer);

        boolean b = refreshScore(answer.getAnswerSheetId());
        return b;
    }

    // 返回 真  结束评分
    private boolean refreshScore(String answerSheetId) {
        AnswerSheet byId = findById(answerSheetId);
        List<Answer> list = answerService.findByAnswerSheetId(answerSheetId);
        Double sumCore = 0.0;
        Double objCore = 0.0;
        Double subCore = 0.0;
        for (Answer answer : list) {
            PaperQuestionRelation relation = relationService.findById(answer.getPaperQuestionId());
            Question question = questionService.findById(relation.getQuestionId());
            Question.Type type = Question.Type.valueOf(question.getType());
            Double score = ObjectEx.get(() -> answer.getScore(), 0.0);
            if (type.equals(Question.Type.FreeResponse) || type.equals(Question.Type.Completion)) {
                // 主觀
                subCore += score;
            } else {
                // 客觀
                objCore += score;
            }
        }
        sumCore = subCore + objCore;
        byId.setObjectiveScore(objCore);
        byId.setSubjectiveScore(subCore);
        byId.setScore(sumCore);
        save(byId);


        boolean flag = true;
        for (Answer answer : list) {
            if (answer.getScore() == null) {
                flag = false;
                break;
            }
        }

        if (flag){
            byId.setResolve(true);
            save(byId);
        }

        return flag;
    }
}
